package main

import (
	"encoding/binary"
	"fmt"
	"github.com/tarm/serial"
	"log"
	"time"
)

const (
	INDEX_CmdHead = 0
	INDEX_Type = 2
	INDEX_Len = 3
	INDEX_Cmd = 4
	INDEX_ID = 4
	INDEX_Buff = 5
)

const (
	//数据模式
	TYPE_CMD  = 0  //命令
	TYPE_DATA = 1  //数据
	TYPE_ACK  = 0xFF
)

/**********************命令请求*****************************/
const (
	//允许注册
	CmdRequest_RegisterPermit       =0x04
	//Reset并重新建立网络
	CmdRequest_Reset                =0x08
	//设置RTC
	CmdRequest_SetRTC               =0x10
	//自组网系统状态
	CmdRequest_NetStatus            =0x11
	//读取版本信息
	CmdRequest_ReadVer              =0xC1
	//读取信道和PanID
	CmdRequest_ReadChanAndPanID     =0xE1
	//设置信道和PanID
	CmdRequest_WriteChanAndPanID    =0xE0
)


/**********************命令回应*****************************/
const (
	//允许注册
	CmdAck_RegisterPermit           =0x04
	//注册时间到
	CmdAck_RegisterTimeOut          =0x06
	//Reset并重新建立网络
	CmdAck_Reset                    =0x08
	//设置RTC
	CmdAck_WriteRTC                 =0x10
	//自组网系统状态
	CmdAck_ReadNetStatus            =0x11
	//读取版本信息
	CmdAck_ReadVer                  =0xC1
	//读取信道和PanID
	CmdAck_ReadChanAndPanID         =0xE1
	//设置信道和PanID
	CmdAck_WriteChanAndPanID        =0xE0
)


/**********************数据解析结果*************************/
const (
	//接收到错误数据，比如数据头错误，校验错误
	Thread_RecvError                =0xFF
	//注册
	Thread_RegisterPermitAck        =0x01
	//应答信号
	Thread_CmdAck                   =0x02
	//接收到透传数据
	Thread_RecvData                 =0x03
	//读取版本信息
	Thread_ReadVerAck               =0xC1
	//读取信道和PanID
	Thread_ReadChanAndPanIDAck      =0xE0
	//设置信道和PanID
	Thread_WriteChanAndPanIDAck     =0xE1
	//设置RTC
	Thread_WriteRTCAck              =0x10
	//读取网络状态
	Thread_ReadNetStatusAck         =0x11
)

var CmdHead = [2]byte{0xFE,0xA5}

var threadModuleSerial *serial.Port

var (
	NodeNetStatus  []byte

	//SystemID    uint16
	//Chan        byte
	SVer        	 byte
	HVer             byte
	NetStatus   	 [50]threadModuleNodeParam
	TD200NetParam    threadModuleNetParam
)

type threadModuleNodeParam struct {
	Addr    string  	`json:"Addr"`
	Network string		`json:"Network"`
}

type threadModuleNetParam struct {
	Chan     byte  	    `json:"Chan"`
	SystemID uint16		`json:"SystemID"`
}

func threadModuleOpenPort(name string){

	log.SetFlags(log.Lmicroseconds)

	c := &serial.Config{Name: name, Baud: 9600,ReadTimeout:1*time.Microsecond}
	var err error
	threadModuleSerial, err = serial.OpenPort(c)
	if err != nil {
		log.Println(err)
	}

	NodeNetStatus = make([]byte,50)
}

func threadModuleWriteBuffer(wData []byte){

	threadModuleSerial.Write(wData)

	buf := make([]byte, 128)
	rCnt, err := threadModuleSerial.Read(buf)
	log.Println(err)

	log.Printf("rCnt %d\n",rCnt)
	if rCnt > 0 {
		log.Println(buf[:rCnt])
	}
}

//获取节点网络状态
func threadModuleGetNodeNetStatus() []byte{
	return NodeNetStatus
}

//获取节点网络参数
func threadModuleGetNetParam() threadModuleNetParam{
	return TD200NetParam
}

//获取软件版本，硬件版本
func threadModuleGetSVer() (byte,byte){
	return SVer,HVer
}

func threadModuleLogHex(dir int,buf []byte){

	var outStr string

	if dir == 0{
		outStr = fmt.Sprintf("Tx-%02d: ",len(buf))
	}else{
		outStr = fmt.Sprintf("Rx-%02d: ",len(buf))
	}

	for _,v:= range buf{
		outStr += fmt.Sprintf("%02X ",v)
	}
	log.Println(outStr)
}

func threadModuleCheckCRC(buf []byte,bufLen int) bool{

	var crc byte = 0

	if bufLen <= 2{
		return false
	}

	var i int
	for i=0;i<(bufLen-3);i++{
		crc += buf[i+INDEX_Type]
	}

	if crc == buf[buf[INDEX_Len]+4]{
		return true
	}else{
		return false
	}
}

func threadModuleGetCRC(buf []byte,bufLen byte) byte{

	var crc byte = 0
	var i byte

	for i=0;i<bufLen;i++{
		crc += buf[i+INDEX_Type]
	}

	return crc
}

func threadModuleCommState(txBuf []byte,txBufLen int) (int,[]byte){

	var (
		totalRxBufCnt int = 0
		preRxBufCnt   int = 0
		curRxBufCnt   int = 0
		err           error
	)
	threadModuleLogHex(0,txBuf[:txBufLen])
	threadModuleSerial.Write(txBuf[:txBufLen])

	rxBufTemp := make([]byte, 256)
	rxBuf := make([]byte, 0)
	var timeOut int16 = 0
	for {
		curRxBufCnt, err = threadModuleSerial.Read(rxBufTemp)
		if err != nil{
			//log.Println("read err,",err)
		}
		totalRxBufCnt += curRxBufCnt
		//2次判断数据长度没有变，表示接收完成
		if totalRxBufCnt==preRxBufCnt && totalRxBufCnt>0 {
			threadModuleLogHex(1,rxBuf[:totalRxBufCnt])
			break
		}else if curRxBufCnt > 0{
			rxBuf = append(rxBuf,rxBufTemp[:curRxBufCnt]...)
			//log.Printf("rxBufcnt %d\n",curRxBufCnt)
			//log.Printf("rxbuftemp %x\n",rxBufTemp[:curRxBufCnt])
			preRxBufCnt = totalRxBufCnt
		}
		time.Sleep(10 * time.Millisecond)
		timeOut = timeOut + 1
		if timeOut >= 15{
			log.Println("wait timeout")
			break
		}
	}

	return totalRxBufCnt,rxBuf[:totalRxBufCnt]
}

func threadModuleProcessRx(rxBuf []byte,rxBufLen int) (int,[]byte,byte){

	var index     int  = 0
	var cmdStatus int   = 0

	appBuf := make([]byte,0)
	var appBufLen byte = 0

	if rxBufLen < 5{
		return Thread_RecvError,appBuf,appBufLen
	}

	for {
		if index < rxBufLen{
			if rxBuf[index]==0xFE && rxBuf[index+1]==0xA5{
				if threadModuleCheckCRC(rxBuf,rxBufLen){
					if rxBuf[INDEX_Type+index] == TYPE_CMD{//命令包回应
						if rxBuf[INDEX_Cmd+index] == CmdAck_RegisterPermit{

						}else if rxBuf[INDEX_Cmd+index] == CmdAck_RegisterTimeOut{

						}else if rxBuf[INDEX_Cmd+index] == CmdAck_ReadVer{
							cmdStatus = Thread_ReadVerAck
							appBufLen = rxBuf[INDEX_Len+index]
							appBuf = append(appBuf,rxBuf[INDEX_Buff:INDEX_Buff+appBufLen]...)

						}else if rxBuf[INDEX_Cmd+index] == CmdAck_ReadChanAndPanID{
							cmdStatus = Thread_ReadChanAndPanIDAck
							appBufLen = rxBuf[INDEX_Len+index]
							appBuf = append(appBuf,rxBuf[INDEX_Buff:INDEX_Buff+appBufLen]...)

						}else if rxBuf[INDEX_Cmd+index] == CmdAck_WriteChanAndPanID{
							cmdStatus = Thread_WriteChanAndPanIDAck
							appBufLen = rxBuf[INDEX_Len+index]
							appBuf = append(appBuf,rxBuf[INDEX_Buff:INDEX_Buff+appBufLen]...)

						}else if rxBuf[INDEX_Cmd+index] == CmdAck_WriteRTC{
							cmdStatus = Thread_WriteRTCAck
							appBufLen = rxBuf[INDEX_Len+index]
							appBuf = append(appBuf,rxBuf[INDEX_Buff:INDEX_Buff+appBufLen]...)

						}else if rxBuf[INDEX_Cmd+index] == CmdAck_ReadNetStatus{
							cmdStatus = Thread_ReadNetStatusAck
							log.Println("Thread_ReadNetStatusAck")
							appBufLen = rxBuf[INDEX_Len+index]
							appBuf = append(appBuf,rxBuf[INDEX_Buff:INDEX_Buff+appBufLen]...)
						}
					}else if rxBuf[INDEX_Type+index] == TYPE_DATA{  //数据包回应
						log.Println("Thread_DATA Ack")
						cmdStatus = Thread_RecvData
						appBufLen = rxBuf[INDEX_Len+index]
						appBuf = append(appBuf,rxBuf[INDEX_ID:INDEX_ID+appBufLen]...)
					}else if rxBuf[INDEX_Type+index] == TYPE_ACK{   //确认包回应

						cmdStatus = Thread_CmdAck
					}
				}
			}
			index++
		}else{
			break
		}
	}

	return cmdStatus,appBuf,appBufLen
}

//获取网络运行状态
func threadModuleReadNetStatus() bool{

	var (
		crc      byte = 0
		txBufLen int = 0
	)

	txBuf := make([]byte,6)

	//-------组包
	txBuf[INDEX_CmdHead] = 0xFE
	txBuf[INDEX_CmdHead+1] = 0xA5
	txBuf[INDEX_Type] = TYPE_CMD
	txBuf[INDEX_Len]  = 0x01
	txBuf[INDEX_Cmd]  = CmdRequest_NetStatus

    crc = threadModuleGetCRC(txBuf,3)
	txBuf[INDEX_Cmd+1] = crc
	txBufLen = 6

	//-------发送
	rxBuf := make([]byte,1024)
	var rxBufLen int = 0
	rxBufLen,rxBuf = threadModuleCommState(txBuf,txBufLen)
	if rxBufLen > 0{
		cmdAck,appBuf,_ := threadModuleProcessRx(rxBuf,rxBufLen)
		if cmdAck == Thread_ReadNetStatusAck {
			copy(NodeNetStatus,appBuf[:50])
			for k,v:= range NodeNetStatus {
				NetStatus[k].Addr = string(k)
				NetStatus[k].Network = string(v)
			}
			log.Println(NodeNetStatus)

			return true
		}
	}

	return false
}

//获取网络参数
func threadModuleReadNetParam() bool{

	var (
		crc      byte = 0
		txBufLen int = 0
	)

	txBuf := make([]byte,6)

	//-------组包
	txBuf[INDEX_CmdHead] = 0xFE
	txBuf[INDEX_CmdHead+1] = 0xA5
	txBuf[INDEX_Type] = TYPE_CMD
	txBuf[INDEX_Len]  = 0x01
	txBuf[INDEX_Cmd]  = CmdRequest_ReadChanAndPanID

	crc = threadModuleGetCRC(txBuf,3)
	txBuf[INDEX_Cmd+1] = crc
	txBufLen = 6

	//-------发送
	rxBuf := make([]byte,1024)
	var rxBufLen int = 0
	rxBufLen,rxBuf = threadModuleCommState(txBuf,txBufLen)
	if rxBufLen > 0{
		cmdAck,appBuf,_ := threadModuleProcessRx(rxBuf,rxBufLen)
		if cmdAck == Thread_ReadChanAndPanIDAck {
			TD200NetParam.Chan = appBuf[0]
			TD200NetParam.SystemID = binary.BigEndian.Uint16(appBuf[1:])
			log.Println("Chan:",TD200NetParam.Chan)
			log.Println("SystemID:",TD200NetParam.SystemID)

			return true
		}
	}

	return false
}

//设置网络参数
func threadModuleWriteNetParam(netParam threadModuleNetParam) bool{

	var (
		crc      byte = 0
		txBufLen int = 0
	)

	txBuf := make([]byte,10)

	//-------组包
	txBuf[INDEX_CmdHead] = 0xFE
	txBuf[INDEX_CmdHead+1] = 0xA5
	txBuf[INDEX_Type] = TYPE_CMD
	txBuf[INDEX_Len]  = 0x04
	txBuf[INDEX_Cmd]  = CmdRequest_WriteChanAndPanID
	txBuf[INDEX_Buff]  = netParam.Chan
	txBuf[INDEX_Buff+1]  = byte(netParam.SystemID/256)
	txBuf[INDEX_Buff+2]  = byte(netParam.SystemID%256)

	crc = threadModuleGetCRC(txBuf,8)
	txBuf[INDEX_Buff+3] = crc
	txBufLen = 9

	//-------发送
	rxBuf := make([]byte,1024)
	var rxBufLen int = 0
	rxBufLen,rxBuf = threadModuleCommState(txBuf,txBufLen)
	if rxBufLen > 0{
		cmdAck,_,_ := threadModuleProcessRx(rxBuf,rxBufLen)
		if cmdAck == Thread_WriteChanAndPanIDAck {

			return true
		}
	}

	return false
}

//获取软件版本
func threadModuleReadSoftVer() bool{

	var (
		crc      byte = 0
		txBufLen int = 0
	)

	txBuf := make([]byte,6)

	//-------组包
	txBuf[INDEX_CmdHead] = 0xFE
	txBuf[INDEX_CmdHead+1] = 0xA5
	txBuf[INDEX_Type] = TYPE_CMD
	txBuf[INDEX_Len]  = 0x01
	txBuf[INDEX_Cmd]  = CmdRequest_ReadVer

	crc = threadModuleGetCRC(txBuf,3)
	txBuf[INDEX_Cmd+1] = crc
	txBufLen = 6

	//-------发送
	rxBuf := make([]byte,1024)
	var rxBufLen int = 0
	rxBufLen,rxBuf = threadModuleCommState(txBuf,txBufLen)
	if rxBufLen > 0{
		cmdAck,appBuf,_ := threadModuleProcessRx(rxBuf,rxBufLen)
		if cmdAck == Thread_ReadVerAck {
			SVer  = appBuf[1]
			HVer  = appBuf[2]
			return true
		}
	}

	return false
}

func threadModuleGetSystemRTC() []byte{

	curTime := time.Now()

	curTimeBuf := make([]byte,6)
	curTimeBuf[0] = byte(curTime.Year()-2000)
	curTimeBuf[1] = byte(curTime.Month())
	curTimeBuf[2] = byte(curTime.Day())
	curTimeBuf[3] = byte(curTime.Hour())
	curTimeBuf[4] = byte(curTime.Minute())
	curTimeBuf[5] = byte(curTime.Second())

	return curTimeBuf
}

//设置网络参数
func threadModuleWriteRTC(rtc []byte) bool{

	var (
		crc      byte = 0
		txBufLen int = 0
	)

	txBuf := make([]byte,12)

	//-------组包
	txBuf[INDEX_CmdHead] = 0xFE
	txBuf[INDEX_CmdHead+1] = 0xA5
	txBuf[INDEX_Type] = TYPE_CMD
	txBuf[INDEX_Len]  = 0x07
	txBuf[INDEX_Cmd]  = CmdRequest_SetRTC
	txBuf[INDEX_Buff]  = rtc[0]
	txBuf[INDEX_Buff+1]  = rtc[1]
	txBuf[INDEX_Buff+2]  = rtc[2]
	txBuf[INDEX_Buff+3]  = rtc[3]
	txBuf[INDEX_Buff+4]  = rtc[4]
	txBuf[INDEX_Buff+5]  = rtc[5]

	crc = threadModuleGetCRC(txBuf,9)
	txBuf[INDEX_Buff+6] = crc
	txBufLen = 12

	//-------发送
	rxBuf := make([]byte,1024)
	var rxBufLen int = 0
	rxBufLen,rxBuf = threadModuleCommState(txBuf,txBufLen)
	if rxBufLen > 0{
		cmdAck,_,_ := threadModuleProcessRx(rxBuf,rxBufLen)
		if cmdAck == Thread_WriteRTCAck {

			return true
		}
	}

	return false
}

//发送透传数据
func threadModuleWriteData(addr byte,buf []byte) (bool,[]byte){

	var (
		crc      byte = 0
		txBufLen int = 0
	)

	txBuf := make([]byte,5)

	//-------组包
	txBuf[INDEX_CmdHead] = 0xFE
	txBuf[INDEX_CmdHead+1] = 0xA5
	txBuf[INDEX_Type] = TYPE_DATA
	txBuf[INDEX_Len]  = byte(len(buf)+1)
	txBuf[INDEX_ID]  = addr
	txBuf = append(txBuf,buf...)

	crc = threadModuleGetCRC(txBuf,byte(len(buf)+3))
	//txBuf[INDEX_Buff+byte(len(buf)+5)] = crc
	txBuf = append(txBuf,crc)

	txBufLen = len(buf)+6

	//-------发送
	rxBuf := make([]byte,1024)
	var rxBufLen int = 0
	rxBufLen,rxBuf = threadModuleCommState(txBuf,txBufLen)
	if rxBufLen > 0{
		cmdAck,ack,_ := threadModuleProcessRx(rxBuf,rxBufLen)
		if cmdAck == Thread_RecvData {
			return true,ack
		}
	}
	return false,nil
}


